/**
 ******************************************************************************
 * @file           : bsp_iic_gpio.c
 * @brief          : GPIO-based I2C (Software I2C) Driver Implementation (STM32F1xx)
 ******************************************************************************
 * @attention
 *
 * GPIO模拟I2C（软件I2C）驱动程序实现文件
 * 基于GPIO模拟I2C通信协议
 * 支持标准I2C时序：START、STOP、ACK、NACK
 * 提供完整的字节级和高级读写接口
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/IIC_GPIO/bsp_iic_gpio.h"
#include "./BSP/IIC_GPIO/bsp_iic_gpio_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* IIC IO操作宏 */
#define IIC_SCL(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)

#define IIC_SDA(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)

#define IIC_READ_SDA()    HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN)

/* Private variables ---------------------------------------------------------*/
static volatile IIC_State_e sg_iic_state = IIC_STATE_IDLE;  /*!< IIC当前状态 */
static volatile uint8_t sg_iic_initialized = 0;             /*!< 初始化标志 */

/* Private function prototypes -----------------------------------------------*/
static void iic_delay(void);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       IIC延时函数
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        控制IIC通信速度，确保时序满足IIC协议要求
 * @note        延时2us，通信速度约250KHz
 */
static void iic_delay(void)
{
    IIC_DELAY_US(IIC_DELAY_TIME_US);
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       IIC初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置SCL和SDA引脚为GPIO模式
 * @note        SCL配置为推挽输出，SDA配置为开漏输出
 * @note        初始化完成后发送停止信号，确保总线空闲
 */
void iic_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    /* 使能GPIO时钟 */
    IIC_SCL_GPIO_CLK_ENABLE();
    IIC_SDA_GPIO_CLK_ENABLE();

    /* 配置SCL引脚 - 推挽输出 */
    gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);

    /* 配置SDA引脚 - 开漏输出 */
    gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);

    /* 停止总线上所有设备，确保总线空闲 */
    iic_stop();

    /* 设置状态 */
    sg_iic_state = IIC_STATE_IDLE;
    sg_iic_initialized = 1;

    log_i("IIC初始化完成");
}

/**
 * @brief       IIC反初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        释放IIC资源
 */
void iic_deinit(void)
{
    if (!sg_iic_initialized)
    {
        return;
    }

    /* 反初始化GPIO */
    HAL_GPIO_DeInit(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN);
    HAL_GPIO_DeInit(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN);

    /* 清除标志 */
    sg_iic_initialized = 0;
    sg_iic_state = IIC_STATE_IDLE;

    log_i("IIC已反初始化");
}

/**
 * @brief       产生IIC起始信号
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        起始信号时序：SCL为高期间，SDA从高变低
 * @note        起始信号后，IIC总线进入忙状态
 */
void iic_start(void)
{
    IIC_SDA(1);
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(0);     /* START信号: 当SCL为高时, SDA从高变成低 */
    iic_delay();
    IIC_SCL(0);     /* 钳住IIC总线，准备发送或接收数据 */
    iic_delay();

    sg_iic_state = IIC_STATE_BUSY;
}

/**
 * @brief       产生IIC停止信号
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        停止信号时序：SCL为高期间，SDA从低变高
 * @note        停止信号后，IIC总线进入空闲状态
 */
void iic_stop(void)
{
    IIC_SDA(0);
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(1);     /* STOP信号: 当SCL为高时, SDA从低变成高 */
    iic_delay();

    sg_iic_state = IIC_STATE_IDLE;
}

/**
 * @brief       等待从机ACK应答信号
 *
 * @param       无
 *
 * @retval      0 接收到ACK
 * @retval      1 未收到ACK（超时）
 *
 * @note        主机释放SDA线，等待从机拉低SDA表示应答
 * @note        如果超时未收到应答，自动发送停止信号
 */
uint8_t iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t result = 0;

    IIC_SDA(1);     /* 主机释放SDA线，允许从机控制SDA */
    iic_delay();
    IIC_SCL(1);     /* 拉高SCL，从机可以在此时发送ACK */
    iic_delay();

    while (IIC_READ_SDA())  /* 等待从机拉低SDA（ACK信号） */
    {
        waittime++;
        if (waittime > IIC_ACK_TIMEOUT)
        {
            iic_stop();     /* 超时，发送停止信号 */
            result = 1;
            sg_iic_state = IIC_STATE_ERROR;
            break;
        }
    }

    IIC_SCL(0);     /* 拉低SCL，结束ACK检查 */
    iic_delay();
    return result;
}

/**
 * @brief       主机发送ACK应答信号
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        ACK时序：在SCL高电平期间，SDA保持低电平
 */
void iic_ack(void)
{
    IIC_SDA(0);     /* 拉低SDA，准备发送ACK */
    iic_delay();
    IIC_SCL(1);     /* 拉高SCL，在SCL高电平期间SDA=0表示ACK */
    iic_delay();
    IIC_SCL(0);     /* 拉低SCL，结束ACK信号 */
    iic_delay();
    IIC_SDA(1);     /* 释放SDA线，恢复空闲状态 */
    iic_delay();
}

/**
 * @brief       主机发送NACK应答信号
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        NACK时序：在SCL高电平期间，SDA保持高电平
 */
void iic_nack(void)
{
    IIC_SDA(1);     /* 拉高SDA，准备发送NACK */
    iic_delay();
    IIC_SCL(1);     /* 拉高SCL，在SCL高电平期间SDA=1表示NACK */
    iic_delay();
    IIC_SCL(0);     /* 拉低SCL，结束NACK信号 */
    iic_delay();
}

/**
 * @brief       IIC发送一个字节
 *
 * @param[in]   data 要发送的数据字节
 *
 * @retval      无
 *
 * @note        高位先发送，发送完成后释放SDA线等待ACK
 */
void iic_send_byte(uint8_t data)
{
    uint8_t i;

    for (i = 0; i < 8; i++)
    {
        IIC_SDA((data & 0x80) >> 7);    /* 设置SDA数据位（高位先发送） */
        iic_delay();
        IIC_SCL(1);     /* 产生时钟脉冲，从机在SCL高电平期间读取数据 */
        iic_delay();
        IIC_SCL(0);     /* 拉低SCL，准备发送下一位 */
        data <<= 1;     /* 左移1位，准备发送下一位 */
    }

    IIC_SDA(1);     /* 发送完成，释放SDA线等待ACK */
}

/**
 * @brief       IIC接收一个字节
 *
 * @param[in]   ack 应答控制(1:发送ACK, 0:发送NACK)
 *
 * @retval      接收到的数据字节
 *
 * @note        高位先接收，接收完成后根据参数发送ACK或NACK
 */
uint8_t iic_recv_byte(uint8_t ack)
{
    uint8_t i, receive_data = 0;

    for (i = 0; i < 8; i++)
    {
        receive_data <<= 1;     /* 高位先接收，先收到的数据位要左移 */
        IIC_SCL(1);             /* 产生时钟脉冲，在SCL高电平期间读取SDA */
        iic_delay();

        if (IIC_READ_SDA())     /* 读取SDA数据位 */
        {
            receive_data++;     /* 读取到高电平，数值加1 */
        }

        IIC_SCL(0);     /* 拉低SCL，准备接收下一位 */
        iic_delay();
    }

    /* 根据参数决定发送ACK还是NACK */
    if (ack)
    {
        iic_ack();      /* 发送ACK，表示继续接收 */
    }
    else
    {
        iic_nack();     /* 发送NACK，表示接收结束 */
    }

    return receive_data;
}

/**
 * @brief       IIC写多个字节
 *
 * @param[in]   addr 设备地址(7位地址)
 * @param[in]   reg  寄存器地址
 * @param[in]   data 数据指针
 * @param[in]   len  数据长度
 *
 * @retval      IIC_OK         写入成功
 * @retval      IIC_ERROR_PARAM 参数错误
 * @retval      IIC_ERROR_NACK  接收到NACK
 *
 * @note        自动添加起始和停止信号
 */
IIC_Error_e iic_write_bytes(uint8_t addr, uint8_t reg, const uint8_t *data, uint16_t len)
{
    uint16_t i;

    /* 参数检查 */
    if (data == NULL || len == 0)
    {
        log_w("写入参数错误: data=%p, len=%d", data, len);
        return IIC_ERROR_PARAM;
    }

    if (!sg_iic_initialized)
    {
        log_e("IIC未初始化");
        return IIC_ERROR_PARAM;
    }

    sg_iic_state = IIC_STATE_TX;

    /* 发送起始信号 */
    iic_start();

    /* 发送设备地址+写 */
    iic_send_byte((addr << 1) | 0);
    if (iic_wait_ack())
    {
        log_w("设备地址0x%02X无应答(写)", addr);
        return IIC_ERROR_NACK;
    }

    /* 发送寄存器地址 */
    iic_send_byte(reg);
    if (iic_wait_ack())
    {
        log_w("寄存器地址0x%02X无应答", reg);
        return IIC_ERROR_NACK;
    }

    /* 发送数据 */
    for (i = 0; i < len; i++)
    {
        iic_send_byte(data[i]);
        if (iic_wait_ack())
        {
            log_w("数据字节%d无应答", i);
            return IIC_ERROR_NACK;
        }
    }

    /* 发送停止信号 */
    iic_stop();

    sg_iic_state = IIC_STATE_IDLE;
    log_d("写入成功: addr=0x%02X, reg=0x%02X, len=%d", addr, reg, len);

    return IIC_OK;
}

/**
 * @brief       IIC读多个字节
 *
 * @param[in]   addr 设备地址(7位地址)
 * @param[in]   reg  寄存器地址
 * @param[out]  data 数据指针
 * @param[in]   len  数据长度
 *
 * @retval      IIC_OK         读取成功
 * @retval      IIC_ERROR_PARAM 参数错误
 * @retval      IIC_ERROR_NACK  接收到NACK
 *
 * @note        自动添加起始和停止信号
 */
IIC_Error_e iic_read_bytes(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t len)
{
    uint16_t i;

    /* 参数检查 */
    if (data == NULL || len == 0)
    {
        log_w("读取参数错误: data=%p, len=%d", data, len);
        return IIC_ERROR_PARAM;
    }

    if (!sg_iic_initialized)
    {
        log_e("IIC未初始化");
        return IIC_ERROR_PARAM;
    }

    sg_iic_state = IIC_STATE_RX;

    /* 发送起始信号 */
    iic_start();

    /* 发送设备地址+写（先写寄存器地址） */
    iic_send_byte((addr << 1) | 0);
    if (iic_wait_ack())
    {
        log_w("设备地址0x%02X无应答(写)", addr);
        return IIC_ERROR_NACK;
    }

    /* 发送寄存器地址 */
    iic_send_byte(reg);
    if (iic_wait_ack())
    {
        log_w("寄存器地址0x%02X无应答", reg);
        return IIC_ERROR_NACK;
    }

    /* 重新发送起始信号（Repeated Start） */
    iic_start();

    /* 发送设备地址+读 */
    iic_send_byte((addr << 1) | 1);
    if (iic_wait_ack())
    {
        log_w("设备地址0x%02X无应答(读)", addr);
        return IIC_ERROR_NACK;
    }

    /* 读取数据 */
    for (i = 0; i < len; i++)
    {
        if (i == len - 1)
        {
            data[i] = iic_recv_byte(0);  /* 最后一个字节发送NACK */
        }
        else
        {
            data[i] = iic_recv_byte(1);  /* 中间字节发送ACK */
        }
    }

    /* 发送停止信号 */
    iic_stop();

    sg_iic_state = IIC_STATE_IDLE;
    log_d("读取成功: addr=0x%02X, reg=0x%02X, len=%d", addr, reg, len);

    return IIC_OK;
}

/**
 * @brief       IIC写单个字节
 *
 * @param[in]   addr 设备地址(7位地址)
 * @param[in]   reg  寄存器地址
 * @param[in]   data 要写入的数据
 *
 * @retval      IIC_OK         写入成功
 * @retval      IIC_ERROR_NACK  接收到NACK
 *
 * @note        简化的单字节写入接口
 */
IIC_Error_e iic_write_byte(uint8_t addr, uint8_t reg, uint8_t data)
{
    return iic_write_bytes(addr, reg, &data, 1);
}

/**
 * @brief       IIC读单个字节
 *
 * @param[in]   addr 设备地址(7位地址)
 * @param[in]   reg  寄存器地址
 * @param[out]  data 数据指针
 *
 * @retval      IIC_OK         读取成功
 * @retval      IIC_ERROR_PARAM 参数错误
 * @retval      IIC_ERROR_NACK  接收到NACK
 *
 * @note        简化的单字节读取接口
 */
IIC_Error_e iic_read_byte(uint8_t addr, uint8_t reg, uint8_t *data)
{
    return iic_read_bytes(addr, reg, data, 1);
}

/**
 * @brief       扫描指定设备地址
 *
 * @param[in]   addr 设备地址(7位地址)
 *
 * @retval      IIC_OK         设备存在
 * @retval      IIC_ERROR_NACK  设备不存在
 *
 * @note        通过发送设备地址并检测ACK来判断设备是否存在
 */
IIC_Error_e iic_scan_device(uint8_t addr)
{
    if (!sg_iic_initialized)
    {
        return IIC_ERROR_PARAM;
    }

    iic_start();
    iic_send_byte((addr << 1) | 0);
    
    if (iic_wait_ack())
    {
        return IIC_ERROR_NACK;
    }
    
    iic_stop();
    return IIC_OK;
}

/**
 * @brief       扫描所有IIC设备
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        扫描地址范围0x08~0x77（有效的7位地址）
 * @note        将扫描到的设备地址打印出来
 */
void iic_scan_all_devices(void)
{
    uint8_t addr;
    uint8_t found_count = 0;

    if (!sg_iic_initialized)
    {
        log_e("IIC未初始化");
        return;
    }

    log_i("开始扫描IIC总线...");

    for (addr = 0x08; addr <= 0x77; addr++)
    {
        if (iic_scan_device(addr) == IIC_OK)
        {
            log_i("发现设备: 0x%02X", addr);
            found_count++;
        }
    }

    if (found_count == 0)
    {
        log_i("未发现任何IIC设备");
    }
    else
    {
        log_i("扫描完成，共发现 %d 个设备", found_count);
    }
}

/**
 * @brief       检查设备是否就绪
 *
 * @param[in]   addr  设备地址(7位地址)
 * @param[in]   retry 重试次数
 *
 * @retval      1 设备就绪
 * @retval      0 设备未就绪
 *
 * @note        用于检查设备是否已完成内部操作
 */
uint8_t iic_is_device_ready(uint8_t addr, uint8_t retry)
{
    uint8_t i;

    for (i = 0; i < retry; i++)
    {
        if (iic_scan_device(addr) == IIC_OK)
        {
            return 1;
        }
        delay_ms(1);
    }

    return 0;
}

/**
 * @brief       获取IIC当前状态
 *
 * @param       无
 *
 * @retval      IIC_State_e 当前状态
 *
 * @note        用于状态监控和调试
 */
IIC_State_e iic_get_state(void)
{
    return sg_iic_state;
}

/**
 * @brief       打印IIC当前状态（用于调试）
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        显示初始化状态、当前状态、配置信息等
 */
void iic_print_status(void)
{
    const char *state_str[] = {"IDLE", "BUSY", "TX", "RX", "ERROR"};

    log_i("IIC当前状态:");
    log_i("  初始化状态: %s", sg_iic_initialized ? "已初始化" : "未初始化");
    log_i("  当前状态: %s", state_str[sg_iic_state]);
    log_i("  通信速度: 约%dKHz", 1000 / (IIC_DELAY_TIME_US * 4));
    log_i("  ACK超时: %d", IIC_ACK_TIMEOUT);
}
